#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <cstring>

#include <functional>

namespace YZC
{
    // 设置默认端口和最大backlog
    const int defaultPort = 8080;
    const int maxBacklog = 128;

    // 设置回调函数
    using func_t = std::function<void(int)>;
    // typedef void (*func_t)(int);

    class tcpServer
    {
    public:
        tcpServer(func_t func, int port = defaultPort)
            : _port(port), _callback(func) {}

        void init()
        {
            // 1.创建socket
            _listensock = socket(AF_INET, SOCK_STREAM, 0);
            if (_listensock < 0)
            {
                std::cerr << "sockte err" << std::endl;
                exit(-1);
            }
            std::cout << "socket success" << std::endl;

            // 2 bind绑定fd和端口
            struct sockaddr_in serveraddr;
            memset(&serveraddr, 0, sizeof(serveraddr));
            // 设置地址的信息（协议，ip，端口）
            serveraddr.sin_family = AF_INET;
            serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定任意网卡ip，通常我们访问某一个IP地址是这个服务器的公网网卡IP地址
            serveraddr.sin_port = htons(_port);             // 注意端口16位，2字节需要使用htons。不可
            socklen_t len = sizeof(serveraddr);
            if (bind(_listensock, (struct sockaddr *)&serveraddr, len) < 0)
            {
                std::cerr << "bind err" << std::endl;
                exit(-1);
            }
            std::cout << "bind success" << std::endl;

            // 3 设置sockfd为监听fd
            if (listen(_listensock, maxBacklog) < 0)
            {
                std::cerr << "listen err" << std::endl;
                exit(-1);
            }
            std::cout << "listen success" << std::endl;
        }

        void run()
        {
            while (true)
            {
                struct sockaddr_in clientaddr;
                memset(&clientaddr, 0, sizeof(clientaddr));
                socklen_t len = sizeof(clientaddr);

                int sockfd = accept(_listensock, (struct sockaddr *)&clientaddr, &len);
                if (sockfd < 0)
                {
                    std::cerr << "accept err" << std::endl;
                    exit(-1);
                }
                std::cout << "accept success" << std::endl;

                // 到这里就能通过sockfd进行通信了

                // 通过clientaddr获取对方的ip/port
                std::string clientip = inet_ntoa(clientaddr.sin_addr);
                uint16_t clientport = ntohs(clientaddr.sin_port);
                printf("获取连接成功,对方的ip/port为[%s][%d]", clientip.c_str(), clientport);

                // 执行响应的回调函数处理数据
                _callback(sockfd);

                // 关闭fd
                close(sockfd);
            }
        }

    private:
        int _listensock;
        int _port;
        func_t _callback;
    };

    void serviceIO(int sockfd)
    {
        // 这里仅做简单的数据收发
        while (true)
        {
            char buffer[128] = {0};
            int count = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
            if (count < 0)
            {
                std::cerr << "recv err" << std::endl;
                exit(-1);
            }
            if (count == 0)
            {
                //对方关闭
                break;
            }
            printf("client --> server:%s\n", buffer);

            // 直接将数据返回给client
            count = send(sockfd, buffer, strlen(buffer), 0);
            if (count < 0)
            {
                std::cerr << "send err" << std::endl;
                exit(-1);
            }
        }
        close(sockfd);
    }

}
